#include "VectorMath.h"
#include "Matriz.h"
#include "SEL.h"

//constructor
template<class T>
SEL<T> :: SEL(int n){
    this->mat = Matriz<T> (n, n);
    this->resultados = VectorMath<T> (n);
    this->tInd = VectorMath<T> (n);
}

//constructor con lectura de .in y escritura de .out
template<class T>
SEL<T> :: SEL(const char * archivoIN){
    unsigned incognitas; 
    T resultado, 
      valor;
      
    int fila, 
        columna;
        
    ifstream archIN( archivoIN );
       
    archIN >> incognitas;
    
    this->mat = Matriz<T> (incognitas, incognitas);
    this->resultados = VectorMath<T> (incognitas);
    this->tInd = VectorMath<T> (incognitas);
        
    for(int i = 0; i < incognitas; i++){
        archIN >> resultado;
        tInd[i] = resultado;
    }
    
    for(int i = 0; i< incognitas * incognitas; i++){
        archIN >> fila;
        archIN >> columna;
        archIN >> valor;
        mat[fila][columna] = valor;
    }
    
    archIN.close();
}

//destructor
template<class T>
SEL<T> :: ~SEL(){
}

//getter resultados
template<class T>
VectorMath<T> SEL<T> :: getRes()const{
     return this->resultados;
}

//getter terminos independientes
template<class T>
VectorMath<T> SEL<T> :: getTInd()const{
     return this->tInd;
}

//getter matriz
template<class T>
Matriz<T> & SEL<T> :: getMat(){
    return this->mat;
}

//setter terminos independientes
template<class T>
void SEL<T> :: setTInd(int i, T valor){
     this->tInd[i] = valor;
}

//setter matriz
template<class T>
void SEL<T> :: setMat(int i, int j, T valor){
     this->mat[i][j] = valor;
}

//resolver mediante escalonada
template<class T>
bool SEL<T> :: resolver(){
    
    unsigned columnas = mat.getColumnas() + 1,
             filas = mat.getFilas();
        
    Matriz<T> sist( filas , columnas );
    
    //copio la matriz
    for(unsigned i = 0; i < filas ; i++)
        for(unsigned j = 0; j < columnas - 1 ; j++)
            sist[i][j] = mat[i][j];
    
    //en esa ultima columna le agrego los resultados
    for(unsigned i = 0; i < filas ; i++)
        sist[i][columnas - 1] = tInd[i];
    
    //llevo la matriz a la forma escalonada Gauss-Jordan
    sist = sist.escalonada();
    
    //guardo las incognitas en el VectorMath
    for(unsigned i = 0; i < filas; i++)
        resultados[i] = sist[i][columnas - 1];
    
    return true;
}

//resolver mediante inversa (se usa este metodo)
template<class T>
bool SEL<T> :: resolverPorInv(){
    resultados = mat.inversa() * tInd;
    return true;
}

//error
template<class T>
T SEL<T> :: error()const{
    return (mat * resultados - tInd).norma();
}

//toString
template<class T>
string SEL<T> :: toString(){
    string selToString;
    
    ostringstream stream;

    stream << tInd.toString();
    stream << resultados.toString();
    stream << mat.toString();
    
    selToString = stream.str();

    return selToString;
}

//test
template<class T>
bool SEL<T> :: test(){
    SEL<float> sist(2);
    
    sist.setTInd(0, 3);
    sist.setTInd(1, -1);
    
    sist.setMat(0, 0, 1);
    sist.setMat(0, 1, 1);
    sist.setMat(1, 0, 1);
    sist.setMat(1, 1, -1);
    
    sist.resolverPorInv();
    
    cout << sist;
    
    return true;
}
